package visitor;

import operatori.Impartit;
import operatori.Minus;
import operatori.Ori;
import operatori.Plus;
import functii.elementare.Constanta;
import functii.elementare.Necunoscuta;
import functii.trigonometrice.Cos;
import functii.trigonometrice.Sin;

public class CalculDerivataVisitor extends Visitor {
	
	double rez;
	CalculVisitor calcV;
	
	public CalculDerivataVisitor() {
		rez = 0;
		calcV = new CalculVisitor();
	}
	
	public CalculDerivataVisitor(double rez) {
		this.rez = rez;
		calcV = new CalculVisitor();
	}
	
	
	public void visit(Plus n) {
		if (n.getFStang()!=null && n.getFDrept()!=null) {
			visit(n.getFStang());
			double rez1 = rez;
			visit(n.getFDrept());
			double rez2 = rez;
			rez = rez1 + rez2;
		}
	}

	
	public void visit(Minus n) {
		if (n.getFStang()!=null && n.getFDrept()!=null) {
			visit(n.getFStang());
			double rez1 = rez;
			visit(n.getFDrept());
			double rez2 = rez;
			rez = rez1 - rez2;
		}
	}

	
	public void visit(Impartit n) {
		if (n.getFStang()!=null && n.getFDrept()!=null) {
			visit(n.getFStang());
			double deriv1 = rez;
			visit(n.getFDrept());
			double deriv2 = rez;
			n.getFStang().acceptVisitor(calcV);
			double calc1 = calcV.getRezultat();
			n.getFDrept().acceptVisitor(calcV);
			double calc2 = calcV.getRezultat();
			// asa:
			rez = (deriv1 * calc2 - calc1 * deriv2) / (calc2 * calc2);
			// sau... las un static Calcul(..) in fiecare operator  (aiurea)
			// sau... creez un arbore ce reprezinta expresia derivarii unei 
				// impartiri a 2 constante (c1=calc1, c2=calc2)
				// si aplic CalculVisitor pe ea: 
				// rez = arboreTemp.acceptVisiotor(calcV)
		}

	}

	
	public void visit(Ori n) {
		if (n.getFStang()!=null && n.getFDrept()!=null) {
			visit(n.getFStang());
			double deriv1 = rez;
			visit(n.getFDrept());
			double deriv2 = rez;
			n.getFStang().acceptVisitor(calcV);
			double calc1 = calcV.getRezultat();
			n.getFDrept().acceptVisitor(calcV);
			double calc2 = calcV.getRezultat();
			// ...
			rez = (deriv1 * calc2 + calc1 * deriv2);
			// ...
		}
	}

	
	public void visit(Necunoscuta n) {
		rez = 1;

	}

	
	public void visit(Constanta c) {
		rez = 0;

	}

	
	public void visit(Sin n) {
		if (n.getFStang()!=null) {
			visit(n.getFStang());
			double deriv1 = rez;
			n.getFStang().acceptVisitor(calcV);
			double calc1 = calcV.getRezultat();
			// .. 
			rez = Math.cos(calc1) * deriv1;
			// ..
		}
	}

	
	public void visit(Cos n) {
		if (n.getFStang()!=null) {
			visit(n.getFStang());
			double deriv1 = rez;
			n.getFStang().acceptVisitor(calcV);
			double calc1 = calcV.getRezultat();
			// .. 
			rez = - Math.sin(calc1) * deriv1;
			// ..
		}

	}
	
	
	public String toString() {
		return String.valueOf(rez);
	}
	
	public double getRezultat() {
		return rez;
	}

}
